from flask import Flask
from flask_sqlalchemy import SQLAlchemy  # 导入连接数据库模块
import redis  # 导入redis模块
from flask_wtf.csrf import CSRFProtect  # 开启csrf验证
from flask_session import Session  # 利用这个包将session存到redis数据库
import logging  # 日志使用模块
from logging.handlers import RotatingFileHandler  # 日志使用模块
from config import config_dict  # 从config里面加载所有的配置信息,键调用值,值调用类,类采用继承

# 创建连接数据库对象
db = SQLAlchemy()  # SQLAlchemy内部有一个self.init_app方法,所以下面可以直接db.init_app(app)

redis_store = None  # 定义一个全局变量,下面采用global声明


# #
def setup_logging(log_level):  # 下面的函数调用了这个方法,调用时,也把参数传了进来
    # 设置日志的记录等级
    logging.basicConfig(level=log_level)  # 调试debug级
    # 创建日志记录器，指明日志保存的路径、每个日志文件的最大大小、保存的日志文件个数上限
    file_log_handler = RotatingFileHandler("logs/log", maxBytes=1024 * 1024 * 100, backupCount=10)
    # 创建日志记录的格式 日志等级 输入日志信息的文件名 行数 日志信息
    formatter = logging.Formatter('%(levelname)s %(filename)s:%(lineno)d %(message)s')
    # 为刚创建的日志记录器设置日志记录格式
    file_log_handler.setFormatter(formatter)
    # 为全局的日志工具对象（flask app使用的）添加日志记录器
    logging.getLogger().addHandler(file_log_handler)


# 下面这个函数就为工厂方法
def create_app(config_name):
    app = Flask(__name__)

    # 获取配置类
    config_cls = config_dict[config_name]
    # manage文件调用上面这个函数,把值赋给config_name ,然后由于config_dict是上面导入的
    # 也就是config文件利用 config_name赋值的键(development)对应的值调用了其上面的函数,继承配置文件,
    # 并把debug传过来了 ,所以下面app.config.from_object(config_cls)变成了这样

    # app.config.from_object(Config) 原版本抛弃
    app.config.from_object(config_cls)  #

    # 项目日志设计
    setup_logging(config_cls.LOG_LEVEL)

    # db对象关联,init_app为内部方法,可以查看源代码,因为上面定义了全局变量db = SQLAlchemy()
    # db = SQLAlchemy()这个操作要继承app对象才能使用redis数据库
    db.init_app(app)

    # 创建redis链接对象,类
    global redis_store
    # config_cls 由于一连串的调用,已经拥有了配置文件的所有信息
    redis_store = redis.StrictRedis(host=config_cls.REDIS_HOST, port=config_cls.REDIES_PORT, decode_responses=True)

    # 为flask项目开启csrf验证
    CSRFProtect(app)

    # 创建session对象
    Session(app)

    # 在每次函数调用没有错误的时候开启wtf表单的验证
    @app.after_request
    def after_request(response):
        from flask_wtf.csrf import generate_csrf  # 导入模块,generate_csrf会随机生成
        # 一串字符,并且他会保存在session里面,而且会进行返回,因此可以用参数接收
        csrf_token = generate_csrf()

        # 告诉浏览器生成的内容,在这里前端的post请求还没有产生csrf验证,因此还需要别的操作
        response.set_cookie('csrf_token', csrf_token)
        return response

        # 针对表单设置CSRFProtect点进去在self.protect()点进去,点进self._get_csrf_token()
        # 可以看到csrf从请求头头获取csrf_token或者表单中获取csrf_token
        # 然后请求头又分为两种情况获取'WTF_CSRF_HEADERS', ['X-CSRFToken', 'X-CSRF-Token']
        #headers:{
            # 'X-CSRFToken':getCookie('csrf_token')
        # },


    # 导入自定一过滤器
    from info.utils.commons import do_rank_class
    app.add_template_filter(do_rank_class, 'rank_class')

    # 使用index文件下面的蓝图,对其进行注册
    from info.modules.index import index_blu  # 导入放在这里相当与采用延时处理,避免
    # 循环引用问题出现
    app.register_blueprint(index_blu)

    #
    # 导入蓝图,并对app进行注册
    from info.modules.passport import passport_blu
    app.register_blueprint(passport_blu, url_prefix='/passport')
    # 这个app在函数里面所以执行完药采用返回的模式才能附带结果出去
    return app
